package cn.android666.nopreviewcamera

import android.text.format.DateFormat
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.Executors

class H264Saver {

    @Volatile
    private var mFileOutputStream: FileOutputStream? = null
    private val pool = Executors.newSingleThreadExecutor()
    @Volatile
    private var isCreating = false
    private var writeFirstFrame = true

    /**
     * 因为创建文件是耗时操作，需要开子线程去创建，所以在写文件之前，先判断一下是否创建好了，创建好了就可以开始写文件了。
     * 没创建好之前可以直接丢掉视频数据，创建好了才开始写，这样可以保证视频数据的连续性。
     * 当可以写的时候，还要判断数据是否是关键帧，是关键帧才开始写，这样可以保证视频一开始播放就有画面，不会花屏。
     */
    fun createFile(): Boolean {
        if (mFileOutputStream != null) {
            // 文件流不为空，则状态Ok，可双开始写文件了
            return true
        }

        if (isCreating) {
            return false
        }

        isCreating = true

        // 创建文件是耗时操作，所以放到子线程中执行
        pool.execute {
            if (mFileOutputStream == null) {
                writeFirstFrame = true
                val dir = App.app.getExternalFilesDir(null)
                val file = File(dir, "${DateFormat.format("yyyy-MM-dd-HHmmss", System.currentTimeMillis())}.h264")
                mFileOutputStream = FileOutputStream(file)
                // 如果是第一次保存，因为创建文件是耗时操作，所以创建文件后的这一帧数据就不要了，以保证视频的连续性
            }
            isCreating = false
        }

        return false
    }


    @Synchronized
    fun saveToFile(h264Data: H264Data) {
        val fos = mFileOutputStream
        if (fos == null) {
            createFile()
            Timber.i("文件没创建好")
        } else {
            if (writeFirstFrame) {
                // 如果是写第一帧，需要判断是否是关键帧，是关键帧才开始写，不是关键帧则不写，掉丢它，这样可以保证视频的第一帧绝对是关键帧，不会出现一开始就有花屏的现象。
                if (h264Data.isKeyFrame) {
                    fos.write(h264Data.h264Bytes)
                    writeFirstFrame = false
                }
            } else {
                fos.write(h264Data.h264Bytes)
            }
        }
    }

    @Synchronized
    fun close() {
        mFileOutputStream?.close()
        mFileOutputStream = null
    }


}